#include "maindialog.h"
#include "ui_maindialog.h"

#include <QTcpSocket>
#include <QByteArray>
#include <QDataStream>
#include <QDebug>

// 定义包头结构（与客户端一致）
struct MessageHeader {
    quint32 msg_len;  
};

MainDialog::MainDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::MainDialog)
{
    ui->setupUi(this);

    m_sock = new QTcpServer(this);

    connect(m_sock, &QTcpServer::newConnection, this, &MainDialog::acceptConnection);

    m_sock->listen(QHostAddress::Any, 8888);
}

MainDialog::~MainDialog()
{
    delete ui;
}

void MainDialog::broadcastMessage(const QByteArray &data)
{
    for(QTcpSocket* sock : m_clients)
    {
        sendPacket(sock, data);
    }
}

void MainDialog::acceptConnection()
{
    qDebug() << "有一个新的客户端连接请求到来！";

    QTcpSocket* sockConn = m_sock->nextPendingConnection();

    connect(sockConn, &QTcpSocket::readyRead, this, &MainDialog::recvMsg);
    connect(sockConn, &QTcpSocket::disconnected, this, &MainDialog::connectClosed);

    m_clients.push_back(sockConn);

    ui->labelOnlineCnt->setText(QString("在线人数：%1").arg(m_clients.size()));
}

// 发送带包头的数据包
void MainDialog::sendPacket(QTcpSocket* sock, const QByteArray &data)
{
    if (!sock || sock->state() != QAbstractSocket::ConnectedState) {
        return;
    }
    
    // 构造包头
    MessageHeader header;
    header.msg_len = data.size();  
    
    // 将整个数据包写入字节数组
    QByteArray packet;
    QDataStream stream(&packet, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian);  
    
    // 先写入包头
    stream << header.msg_len;
    
    stream.writeRawData(data.constData(), data.size());
    
    // 发送完整数据包
    sock->write(packet);
}

void MainDialog::on_btnSend_clicked()
{
    // 将聊天消息发送给所有在线客户端
    QString msg = ui->edtMsg->toPlainText();

    // for(QTcpSocket* sock : m_clients)
    // {
    //     sock->write(msg.toUtf8());
    // }
    if (msg.isEmpty()) {
        return;
    }

    //使用封包函数发送数据
    QByteArray messageData = msg.toUtf8();
    broadcastMessage(messageData);
    
    // 清空输入框并在服务器界面显示
    ui->edtMsg->clear();
    ui->edtRecord->appendPlainText(msg + "\n\n");

}

void MainDialog::recvMsg()
{
    // 获取信号发射者的指针
    QTcpSocket* sock = qobject_cast<QTcpSocket*>(sender());

    // 接收当前所有新数据
   // QByteArray data = sock->readAll();

    // 显示在聊天记录框中
    //ui->edtRecord->appendPlainText(QString::fromUtf8(data) + "\n\n");

    // for(QTcpSocket* sock : m_clients)
    // {
    //     sock->write(data);
    // }
    if (!sock) return;

    // 使用静态缓冲区处理每个客户端的数据
    static QMap<QTcpSocket*, QByteArray> clientBuffers;
    
    QByteArray &buffer = clientBuffers[sock];
    buffer.append(sock->readAll());

    while (buffer.size() >= 4) {  // 至少要有包头
        // 解析包头（大端序）
        quint32 msg_len = ((quint8)buffer[0] << 24) |
                         ((quint8)buffer[1] << 16) |
                         ((quint8)buffer[2] << 8) |
                         (quint8)buffer[3];

        // 检查是否收到完整的数据包
        if (static_cast<quint32>(buffer.size()) >= 4 + msg_len) {
            // 提取消息体
            QByteArray messageData = buffer.mid(4, msg_len);
            QString message = QString::fromUtf8(messageData);
            
            // 显示在聊天记录框中
            ui->edtRecord->appendPlainText(message + "\n\n");

            // 广播消息给所有客户端（发送者除外）
            for(QTcpSocket* client : m_clients)
            {
               if (client != sock)
               {
                    sendPacket(client, messageData);
                }
            }

            // 从缓冲区移除已处理的数据
            buffer = buffer.mid(4 + msg_len);
        } 
        else 
        {
            // 数据不完整，等待更多数据
            break;
        }
    }
        
        if (buffer.isEmpty()) 
        {
            clientBuffers.remove(sock);
        }
}

void MainDialog::connectClosed()
{
    // 获取信号发射者的指针
    QTcpSocket* sock = qobject_cast<QTcpSocket*>(sender());

    if (!sock) return;

    m_clients.removeOne(sock);  // 从客户端链表中删除当前下线的客户端

    static QMap<QTcpSocket*, QByteArray> clientBuffers;
    clientBuffers.remove(sock);
    
    ui->labelOnlineCnt->setText(QString("在线人数：%1").arg(m_clients.size()));

    sock->deleteLater();
}
